﻿//========================================================= 
/**@file LogExtension.h
 * @brief 日志Appender扩展模块
 * 
 * @date 2018-07-06   14:28:41
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LOGEXTENSION_H_
#define _LIBZHOUYB_LOGEXTENSION_H_
//--------------------------------------------------------- 
#ifndef NO_INCLUDE_C11_SOURCE
#   include <condition_variable>
#   include <mutex>
#   include <thread>
#   include <memory>
#   include <list>
#endif

#include "../ILogCat.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace extension {
namespace logcat {
//--------------------------------------------------------- 
/// 日志事件
struct LogEvent
{
    LogLevel Lv;
    const char* Tag;
    string Message;
};
/// 带日志输出级别的扩展
template<class TLogAppender>
class LogLv : public TLogAppender
{
    DisableObjConsturctCopyBehavior(LogLv)
public:
    LogLv() : TLogAppender(), Level(LogAll) {}

    virtual void append(LogLevel lv, const char* tag, const char* str)
    {
        if(lv < Level)
            return;
        TLogAppender::append(lv, tag, str);
    }
    LogLevel Level;
};
/// 初始化时进行设置的LogLv
template<class TLogAppender, LogLevel Lv>
struct LogLvWith : public LogLv<TLogAppender>
{
public:
    LogLvWith() : LogLv<TLogAppender>() { LogLv<TLogAppender>::Level = Lv; }
};
/// 支持异步的日志扩展
template<class TLogAppender>
class LogAsync : public TLogAppender
{
    DisableObjConsturctCopyBehavior(LogAsync)
protected:
    ASYNC_USING(async_mutex _mutex);
public:
    LogAsync() : TLogAppender() {}

    virtual void append(LogLevel lv, const char* tag, const char* str)
    {
        ASYNC_LOCK(_mutex);
        TLogAppender::append(lv, tag, str);
    }
};
/// 萃取实际的异步扩展类
template<class T>
struct LogAsyncTraits
{
#ifdef INCLUDE_ASYNC_SOURCE
    typedef LogAsync<T> Type;
#else
    typedef T Type;
#endif
};
#ifndef NO_INCLUDE_C11_SOURCE
/// 带锁的日志扩展
template<class TLogAppender>
class LogLocked : public TLogAppender
{
    DisableObjConsturctCopyBehavior(LogLocked)
protected:
    std::mutex _mutex;
public:
    LogLocked() : TLogAppender() {}

    virtual void append(LogLevel lv, const char* tag, const char* str)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        TLogAppender::append(lv, tag, str);
    }
};
/// 带缓存的日志扩展,提高LogCat输出性能
template<class TLogAppender>
class LogCached : public TLogAppender
{
    DisableObjConsturctCopyBehavior(LogCached)
protected:
    bool _is_running;
    std::mutex _mutex;
    std::condition_variable_any _condition;
    std::list<LogEvent> _queue;
    std::shared_ptr<std::thread> _work_thd;

    void run()
    {
        std::list<LogEvent> logs;
        while(_is_running)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_queue.size() < 1)
                {
                    _condition.wait(lock);
                    continue;
                }
                logs.swap(_queue);
                _queue.clear();
            }
            std::list<LogEvent>::iterator itr;
            for(itr = logs.begin(); _is_running && itr != logs.end(); ++itr)
            {
                TLogAppender::append(itr->Lv, itr->Tag, itr->Message.c_str());
            }
            logs.clear();
        }
    }
public:
    LogCached() : TLogAppender() {}
    virtual ~LogCached()
    {
        if(_is_running)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _is_running = false;
                _queue.clear();
            }
            if(_work_thd != nullptr && _work_thd->joinable())
            {
                _condition.notify_one();
                _work_thd->join();
            }
        }
    }
    virtual void append(LogLevel lv, const char* tag, const char* str)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _queue.push_back(LogEvent());
        LogEvent& logEvent = _queue.back();

        logEvent.Lv = lv;
        logEvent.Tag = tag;
        logEvent.Message = _strput(str);

        if(_work_thd == nullptr)
        {
            _is_running = true;
            _work_thd = std::make_shared<std::thread>(std::bind(&LogCached::run, this));
        }
        _condition.notify_one();
    }
};
#endif
//--------------------------------------------------------- 
} // namespace logcat
} // namespace extension
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LOGEXTENSION_H_
//========================================================= 